/*
  LinkSpriteCam.cpp - Library for flashing Morse code.
  Created by Mike Henrey, June 15 2013.	
  Copyright 2013 Mike Henrey 

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along 
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* For use with Arduino 1.05 */

#include "Arduino.h"
#include "LinkSpriteCam.h"

LinkSpriteCam::LinkSpriteCam()
{
}

void LinkSpriteCam::Seta(int _a)
{
	a = _a;
}

int LinkSpriteCam::Geta()
{
	return a;
}

void LinkSpriteCam::Decreasea(int decreaseAmount)
{
	a -= decreaseAmount;
}

boolean LinkSpriteCam::Begin(int baudRate, int _readBuffSize, int _spacingInterval)
{
	Serial.begin(38400);
	readBuffSize = _readBuffSize;
	spacingInterval = _spacingInterval;
	return true;
}

boolean LinkSpriteCam::SendResetCmd()
{
  const int RET_MESSAGE_SIZE = 4;
  
	byte retData;
	int initSequenceCount = 0;
	int timeout;
 
 	int zero = 0x00;
	Serial.write(0x56);
  Serial.write(zero);
	Serial.write(0x26);
  Serial.write(zero);
  
  // Now capture the return message
  while(1){
    // wait for data to become ready
    timeout = 0;
    while(!Serial.available()){
      delay(1);
      timeout++;
      if (timeout > TIMEOUT_MAX){
        return(false);
      }
    }
    retData=Serial.read();
    // state machine to read the response "76 00 26 00"
    switch (initSequenceCount){
      case 0:
        if (retData == 0x76){
          initSequenceCount = 1;    // advance the SM on 76
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 1:
        if (retData == 0x00){
          initSequenceCount = 2;    // advance the SM on 00
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 2:
        if (retData == 0x26){
          initSequenceCount = 3;    // advance the SM on 26
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 3:
        if (retData == 0x00){
          return true;
        }
        break;
    }
  }
  return false;
}

boolean LinkSpriteCam::ReadInitSequence()
{
  const int RET_MESSAGE_SIZE = 5;
  
  byte retData;
  int initSequenceCount = 0;
  int timeout;
  while(1){
    // wait for data to become ready
    timeout = 0;
    while(!Serial.available()){
      delay(1);
      timeout++;
      // using a longer timeout because the init takes time
      if (timeout > TIMEOUT_MAX*3){
        return(false);
      }
    }
    retData=Serial.read();
    
    
    // state machine to read the "Init end" response "65 6E 64 0D 0A" (only using last 5 characters)
    switch (initSequenceCount){
    case 0:
      if (retData == 0x65){
        initSequenceCount = 1;    // advance the SM on 65
      }
      else{
        initSequenceCount = 0;
      }
      break;
    case 1:
      if (retData == 0x6E){
        initSequenceCount = 2;    // advance the SM on 6E
      }
      else{
        initSequenceCount = 0;
      }
      break;
    case 2:
      if (retData == 0x64){
        initSequenceCount = 3;    // advance the SM on 64
      }
      else{
        initSequenceCount = 0;
      }
      break;
    case 3:
      if (retData == 0xD){
        initSequenceCount = 4;    // advance the SM on 0D
      }
      else{
        initSequenceCount = 0;
      }
      break;
    case 4:
      if (retData == 0xA){      // complete the action on 0A
        return true;
      }
      break;
    }
  }
  // never gets here
  return false;
}

//Send take picture command
void LinkSpriteCam::SendTakePhotoCmd()
{
  int zero = 0x00;
  Serial.write(0x56);
  Serial.write(zero);
  Serial.write(0x36);
  Serial.write(0x01);
  Serial.write(zero);  
}

void LinkSpriteCam::CheckPhotoCaptured(){
  int k=0;
  int count=0;  
  byte incomingbyte;
  byte serData[32];
  
  while((Serial.available()>0) && (k < 31))   {
    incomingbyte=Serial.read();
    serData[k] = incomingbyte;
    k++;
  }
  count = k;
}

//Read data
void LinkSpriteCam::SendReadDataCmd()
{
  int zero = 0x00;
  MH=a/0x100;
  ML=a%0x100;
  Serial.write(0x56);
  Serial.write(zero);
  Serial.write(0x32);
  Serial.write(0x0c);
  Serial.write(zero); 
  Serial.write(0x0a);
  Serial.write(zero);
  Serial.write(zero);
  Serial.write(MH);
  Serial.write(ML);
  Serial.write(zero);
  Serial.write(zero);
  Serial.write(zero);
  Serial.write(readBuffSize);                // buffer size
  Serial.write(zero);  
  Serial.write(spacingInterval/10);           // time delay between lines
  a+=readBuffSize;                           //address increases 64 set according to buffer size
}

void LinkSpriteCam::StopTakePhotoCmd()
{
  int zero = 0x00;
  Serial.write(0x56);
  Serial.write(zero);
  Serial.write(0x36);
  Serial.write(0x01);
  Serial.write(0x03);        
}

void LinkSpriteCam::StartPowerSavingsCmd(){
  int zero = 0x00;
  Serial.write(0x56);
  Serial.write(zero);
  Serial.write(0x3E);
  Serial.write(0x03);
  Serial.write(zero);
  Serial.write(0x01);
  Serial.write(0x01);  
}

void LinkSpriteCam::StopPowerSavingsCmd(){
  int zero = 0x00;
  Serial.write(0x56);
  Serial.write(zero);
  Serial.write(0x3E);
  Serial.write(0x03);
  Serial.write(zero);
  Serial.write(0x01);
  Serial.write(zero);
}

// returning 0 indicates a failure
word LinkSpriteCam::GetFileSize(){
  int k=0;
  int count=0;
  int timeout=0;
  word photoSize = 0;
  byte incomingbyte;
  byte highSizeByte;
  byte retData;
  int initSequenceCount = 0;
  
  // send the command to get the file size
	int zero = 0x00;
  Serial.write(0x56);
  Serial.write(zero);
  Serial.write(0x34);
  Serial.write(0x01);
  Serial.write(zero);
  
  // now read it back
  // wait for data to become ready
  while(timeout < TIMEOUT_MAX){
		while(!Serial.available()){
			delay(1);
			timeout++;
			if (timeout > TIMEOUT_MAX){
				break;
			}	
		}
		retData=Serial.read();
    // state machine to read the response "76 00 34 00 04 00 00" then the next 2 bytes are the size data
    switch (initSequenceCount){
		case 0:
			if (retData == 0x76){
				initSequenceCount = 1;    // advance the SM on 76
			}
			else{
				initSequenceCount = 0;
			}
			break;
		case 1:
			if (retData == 0x00){
				initSequenceCount = 2;    // advance the SM on 00
			}
			else{
				initSequenceCount = 0;
			}
			break;
		case 2:
			if (retData == 0x34){
				initSequenceCount = 3;    // advance the SM on 54
			}
			else{
				initSequenceCount = 0;
			}
			break;
		case 3:
			if (retData == 0x00){
				initSequenceCount = 4;    // advance the SM on 00
			}
			else{
				initSequenceCount = 0;
			}
			break;
		case 4:
			if (retData == 0x04){
				initSequenceCount = 5;    // advance the SM on 00
			}
			else{
				initSequenceCount = 0;
			}
			break;
		case 5:
			if (retData == 0x00){
				initSequenceCount = 6;    // advance the SM on 00
			}
			else{
				initSequenceCount = 0;
			}
			break;
		case 6:
			if (retData == 0x00){
				initSequenceCount = 7;    // advance the SM on 00
			}
			else{
				initSequenceCount = 0;
			}
			break;
		case 7:
			highSizeByte = retData;			// get the high byte
			initSequenceCount = 8;    // advance the SM on any data
			break;
		case 8:
			return(word(highSizeByte, retData));	// return the data        
			break;
    }
  }
  // timeout condition
  return(0);
}

boolean LinkSpriteCam::SetLargeSizeCmd(){
  
  const int RET_MESSAGE_SIZE = 5;
  
  byte retData;
  int initSequenceCount = 0;
  int timeout;
  
  int zero = 0x00;
  Serial.write(0x56);
  Serial.write(zero);
  Serial.write(0x54);
  Serial.write(0x01);
  Serial.write(zero);
  
  // Now capture the return message
  while(1){
    // wait for data to become ready
    timeout = 0;
    while(!Serial.available()){
      delay(1);
      timeout++;
      if (timeout > TIMEOUT_MAX){
        return(false);
      }
    }
    retData=Serial.read();
    // state machine to read the response "76 00 54 00 00"
    switch (initSequenceCount){
      case 0:
        if (retData == 0x76){
          initSequenceCount = 1;    // advance the SM on 76
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 1:
        if (retData == 0x00){
          initSequenceCount = 2;    // advance the SM on 00
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 2:
        if (retData == 0x54){
          initSequenceCount = 3;    // advance the SM on 54
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 3:
        if (retData == 0x00){
          initSequenceCount = 4;    // advance the SM on 00
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 4:
        if (retData == 0x00){      // complete the action on 00
          return true;
        }
        break;
    }
  }
  return false;
}

// returns size of buffer if completed properly
// returns last position if end flag set
// returns -1 if timed out
int LinkSpriteCam::FillReadBuffer(byte *serData){
  // variables
  int j = 0;
  int timeout = 0;
  int initSequenceCount = 0;
  
  // get a full buffer of data
  while(j<readBuffSize){
    // wait for data to become ready
    timeout = 0;
    while(!Serial.available()){
      delay(1);
      timeout++;
      if (timeout > TIMEOUT_MAX){
        return(-1);
      }
    }
    serData[j]=Serial.read();
    // state machine to eliminate the init sequence "76 00 32 00 00"
    switch (initSequenceCount){
      case 0:
        if (serData[j] == 0x76){
          initSequenceCount = 1;    // advance the SM on 76
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 1:
        if (serData[j] == 0x00){
          initSequenceCount = 2;    // advance the SM on 00
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 2:
        if (serData[j] == 0x32){
          initSequenceCount = 3;    // advance the SM on 32
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 3:
        if (serData[j] == 0x00){
          initSequenceCount = 4;    // advance the SM on 00
        }
        else{
          initSequenceCount = 0;
        }
        break;
      case 4:
        initSequenceCount = 0;    // return to start
        if (serData[j] == 0x00){
          j -= 5;    // subtract 5 from j tp overwrite the init sequence
        }
        else{
          // do nothing
        }
        break;
    }
    
    if (j >= 1){
      if((serData[j-1]==0xFF)&&(serData[j]==0xD9)){      //Check if the picture is over
        return(j+1);      // return, no more processing needed
      }
    }
    j++;
  }
  return(j);
}
